﻿using Library.Logic;
using Library.Logic.Constraints;
using System;
using System.Linq.Expressions;
using TRULE = System.Linq.Expressions.Expression<System.Func<System.Linq.IQueryable<System.Linq.Expressions.Expression>, System.Collections.Generic.IEnumerable<System.Collections.Generic.IEnumerable<System.Linq.Expressions.Expression>>>>;
using TEXPRESSION = System.Linq.Expressions.Expression;

namespace Library.Linq.Expressions
{
    public sealed class VariableExpression : Expression, IHasConstraintsReasonReadOnly, IHasType, ICloneable 
    {
        internal VariableExpression(IConstraintsReasonReadOnly constraints, uint index)
        {
            this.constraints = constraints;
            this.index = index;
            if (!Builtin.InferType(constraints, index, out type))
                type = constraints.InputParameters[0].Type;
        }

        IConstraintsReasonReadOnly constraints;
        uint index;
        Type type;

        public IConstraintsReasonReadOnly Constraints
        {
            get
            {
                return constraints;
            }
        }
        IConstraintsReadOnly IHasConstraintsReadOnly.Constraints
        {
            get { return constraints; }
        }

        public object Clone()
        {
            throw new NotImplementedException();
        }

        public override Type Type
        {
            get
            {
                return type;
            }
        }
        public override ExpressionType NodeType
        {
            get
            {
                return ExpressionType.Extension;
            }
        }
        public override bool CanReduce
        {
            get
            {
                return true;
            }
        }
        public override Expression Reduce()
        {
            return constraints.InputParameters[index];
        }

        public override string ToString()
        {
            return constraints.InputParameters[index].ToString();
        }
    }
}

namespace Library.Logic
{
    public sealed class Variable : IHasConstraintsReason, IHasType, ICloneable
    {
        public Variable()
        {

        }
        internal Variable(IConstraintsReason constraints, uint index)
        {
            this.constraints = constraints;
            this.index = index;
        }

        IConstraintsReason constraints;
        uint index;

        public IConstraintsReason Constraints
        {
            get
            {
                return constraints;
            }
        }
        IConstraintsReasonReadOnly IHasConstraintsReasonReadOnly.Constraints
        {
            get
            {
                return constraints;
            }
        }
        IConstraints IHasConstraints.Constraints
        {
            get { return constraints; }
        }
        IConstraintsReadOnly IHasConstraintsReadOnly.Constraints
        {
            get { return constraints; }
        }

        public Type Type
        {
            get
            {
                Type type;
                return Builtin.InferType(constraints, index, out type) ? type : constraints.InputParameters[0].Type;
            }
        }

        public object Clone()
        {
            return new Variable((IConstraintsReason)this.constraints.Clone(), index);
        }
    }
}

namespace Library.Logic.Semantics
{
    //public interface IVariable : IHasConstraintsReadOnly<FuncOutput<IArgument, IHasIdentifier<Uri>, ISemanticGraphReadOnly, bool>> { }    
}